/* Standard includes */
#include <math.h>
#include <string.h>
#include <stdio.h>

/* External libraries */
#include <allegro.h>
#include <zzip/lib.h>

/* Amazo includes */
#include "include/worlds.h"
#include "include/display.h"
#include "include/logger.h"
#include "include/terrain.h"
#include "include/archiver.h"
#include "include/parser.h"
#include "include/loadpng.h"
#include "include/dynamic_list.h"
#include "include/cli.h"



/* World timer structure */
typedef struct w_timer {
	int frames_left;
	int interval;
	char * function;
} w_timer_t;

/* Globals */
dynlist_t *w_tex = NULL;
dynlist_t *w_timers = NULL;

/* Load matter definitions from a world xml node */
void load_world_matter(ZZIP_DIR * archive, xmlDocPtr doc, xmlNodePtr node)
{
	/* Go through every node below the "matter" node */
	for(node = node->children; node != NULL; node = node->next)
	{
		/* Skip comment and text nodes */
		if(!xmlStrcmp(node->name, "comment") || !xmlStrcmp(node->name, "text"))
			continue;
			 
		int id;
		char * tpath = NULL;
		for(xmlNodePtr desc = node->children; desc != NULL; desc = desc->next)
		{
			// Get the id
			if(!xmlStrcmp(desc->name, "id"))
				id = atoi(xmlNodeListGetString(doc, desc->xmlChildrenNode, 1));
		
			// Texture	
			if(!xmlStrcmp(desc->name, "texture"))
				tpath = xmlNodeListGetString(doc, desc->xmlChildrenNode, 1);
				
			// Timer
			if(!xmlStrcmp(desc->name, "timer"))
			{
				w_timer_t * tim = malloc(sizeof(w_timer_t));
				for(xmlNodePtr t_node = desc->children; t_node != NULL; t_node = t_node->next)
				{
					if(!xmlStrcmp(t_node->name, "interval"))
						tim->interval = atoi(xmlNodeListGetString(doc, t_node->xmlChildrenNode, 1));
					if(!xmlStrcmp(t_node->name, "callback")) {
						char * callback = xmlNodeListGetString(doc, t_node->xmlChildrenNode, 1);
						tim->function = malloc(strlen(callback)+1);
						strcpy(tim->function, callback);
						free(callback);
					}
				}
				tim->frames_left = tim->interval;
				dynlist_push(w_timers, tim);
			}
			
		}
		if(tpath != NULL)
		{
			
			/* Load the png data from zip, create a bitmap out of it, and add it to the list of textures */
			void * buffer = load_file_from_archive(archive, tpath);
			BITMAP * img = load_memory_png(buffer, last_buf_size, NULL);
			free(buffer);
			if(img != NULL) {
				dynlist_push(w_tex, img);
				
				/* show the image */
			}
			else
			{
				
			}
						
		}
	}
	
	/* list test, show all the images that we loaded */
//clear_to_color(screen, makecol(0, 128, 0));
//			while(!key[KEY_ESC]);/*		
/*		BITMAP * bt;
		while(bt = dynlist_pop(w_tex)) {
		
			//blit(bt, screen, 0, 0, 50, 50, bt->w, bt->h);
			clear_to_color(screen, makecol(0, 128, 0));
			textout_ex(screen, font, "Loaded this texture (press ESC and then SPACE): ", 0, 0, makecol(255, 255, 0), -1);
			destroy_bitmap(bt);
			while(!key[KEY_ESC]);
			//while(!key[KEY_SPACE]);
		}*/
}

/* This function  */
void parse_world_node(ZZIP_DIR * archive, xmlDocPtr doc, xmlNodePtr node)
{
	/* Ignore comments */
	if(!strcmp((char*)node->name, "comment")) return;
	
	/* Load matter definitions */
	if(!strcmp((char*)node->name, "matter"))
		load_world_matter(archive, doc, node);
}

void am_destroy_timer(w_timer_t * tim)
{
	printf("Destroying timer: %s\n", tim->function);
	free(tim->function);
	free(tim);
}

void load_world(char * filename)
{
	/* Load the archive */
	ZZIP_DIR* archive = zzip_dir_open(filename,0);
	
	
	w_tex = dynlist_create("World Textures", destroy_bitmap);
	w_timers = dynlist_create("World Timers", am_destroy_timer);
	
	
	/* Load the terrains.xml file into memory */
	unsigned char * xml = load_file_from_archive(archive, "world.xml");
	if(xml == NULL)
		return;
	 
	// * parse the xml here *
	xmlDocPtr doc = xmlParseDoc(xml);
	xmlNodePtr node = NULL;
	
	/* Find the world node first */
	node = xmlDocGetRootElement(doc);
	if(node == NULL || xmlStrcmp(node->name, "world")) {
		return;
	}
	
	/* Parse all the nodes in 'world' and quit the loop */
	for(node = node->children; node != NULL; node = node->next) {
		parse_world_node(archive, doc, node);
	}
	
	// Pretend this is the main loop
	while(!key[KEY_ESC])
	{
		if(key[KEY_TAB])
			am_show_cli(canvas);
		
		clear_to_color(canvas, makecol(0, 0, 128));
		textout_ex(canvas, font, "Press ESC to exit the imaginary loop ...", 10, 10, makecol(255, 255, 0), -1);
		sync();
		
		/* Process timers */
		for(int I = 0; I < w_timers->count; I++)
		{
			w_timer_t * tim = dynlist_get(w_timers, I);
			if(tim->frames_left == 0)
			{
				tim->frames_left = tim->interval;
				printf("Calling lua '%s'\n", tim->function);
			}
			else tim->frames_left-=1;
		}
	};
	
	xmlFreeDoc(doc);	
	
	/* Free memory */
	free(xml);
	zzip_dir_close(archive);
	dynlist_free(&w_timers);
	dynlist_free(&w_tex);
}

void world_demo(char * filename)
{
	load_world(filename);
	
	
	
	return;
	int cl_blue = makecol(0, 0, 128);
	int cl_yellow = makecol(255, 255, 0);
	
	BITMAP * base = load_bitmap("earth.png", NULL);
	TERRAIN * terr = generate_terrain(canvas->w, canvas->h, 100);
	
	int done = 0;
	int redraw = 1;
	while(!done)
	{
		// Process logic at a set rate
		while (frame_lock > 0) {
      			/* Process input */
			if(key[KEY_ESC]) done = 1;
		
			if (mouse_b & 1) {
				for(int I = mouse_x - 16; I < mouse_x + 16; I++)
				for(int J = mouse_y - 16; J < mouse_y + 16; J++)
         			{
         				if(terr->data[J*terr->w + I] != 0
         				&& sqrt(pow(I-mouse_x, 2) + pow(J - mouse_y, 2)) < 16)
         					terr->data[J*terr->w + I] |= 1 << 7;
         			}
         			redraw = 1;
         		}
		
			if(key[KEY_SPACE]) {
				cl_blue = makecol(rand() % 255, rand() % 255, rand() % 255);
				redraw = 1;
			}
		
      			--frame_lock;
   		}

		// Redraw the scene when necessary
   		if (redraw) {
   			redraw = 0;
      			
   			/* Update the scene */
			acquire_screen();
		
			clear_to_color(canvas, cl_blue);
			draw_terrain(canvas, terr, base, 0);
			textprintf_ex(canvas, font, 10, 10, cl_yellow, -1, "FPS: %d", fps);
			
			release_screen();
			sync();
   		} 
   		else 
   			rest(1);	/* don't hog the CPU */
	}
	
	destroy_bitmap(base);
	free_terrain(terr);
	
}
